package com.yinp.proapp.view.viewpager2;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.LinearLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.viewpager2.widget.ViewPager2;

import static androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL;

/**
 * @author :yinpeng
 * date      :2021/9/2
 * package   :com.yinp.proapp.view.viewpager2
 * describe  : 用于解决viewPager的滑动冲突问题
 */
public class NestedScrollableHost extends LinearLayout {
    /*
     * Copyright 2019 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */

    /**
     * Layout to wrap a scrollable component inside a ViewPager2. Provided as a solution to the problem
     * where pages of ViewPager2 have nested scrollable elements that scroll in the same direction as
     * ViewPager2. The scrollable element needs to be the immediate and only child of this host layout.
     * <p>
     * This solution has limitations when using multiple levels of nested scrollable elements
     * (e.g. a horizontal RecyclerView in a vertical RecyclerView in a horizontal ViewPager2).
     */

    private int touchSlop = 0;
    private float initialX = 0f;
    private float initialY = 0f;
    private ViewPager2 parentViewPager;

    private View child = null;


    public NestedScrollableHost(@NonNull Context context) {
        this(context, null);
    }

    public NestedScrollableHost(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
        if (getChildCount() > 0) {
            child = getChildAt(1);
        }
        View view = (View) getParent();
        while (parentViewPager == null) {
            if (view instanceof ViewPager2) {
                parentViewPager = (ViewPager2) view;
            } else {
                if (view != null) {
                    view = (View) view.getParent();
                } else {
                    return;
                }
            }
        }
    }

    private boolean canChildScroll(int orientation, Float delta) {
        int direction = -delta.intValue();
        switch (orientation) {
            case 0:
                if (child != null) {
                    return child.canScrollHorizontally(direction);
                } else {
                    return false;
                }
            case 1:
                if (child != null) {
                    return child.canScrollVertically(direction);
                } else {
                    return false;
                }
        }
        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        handleInterceptTouchEvent(ev);
        return super.onInterceptTouchEvent(ev);
    }

    private void handleInterceptTouchEvent(MotionEvent e) {
        int orientation;
        if (parentViewPager != null) {
            orientation = parentViewPager.getOrientation();
        } else {
            return;
        }

        // Early return if child can't scroll in same direction as parent
        if (!canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f)) {
            return;
        }

        if (e.getAction() == MotionEvent.ACTION_DOWN) {
            initialX = e.getX();
            initialY = e.getY();
            getParent().requestDisallowInterceptTouchEvent(true);
        } else if (e.getAction() == MotionEvent.ACTION_MOVE) {
            float dx = e.getX() - initialX;
            float dy = e.getY() - initialY;
            boolean isVpHorizontal = orientation == ORIENTATION_HORIZONTAL;
            float scaledDx;
            float scaledDy;
            if (isVpHorizontal) {
                scaledDx = Math.abs(dx) * 0.5f;
                scaledDy = Math.abs(dy) * 0.5f;
            } else {
                scaledDx = Math.abs(dx) * 1f;
                scaledDy = Math.abs(dy) * 1f;
            }
            if (scaledDx > touchSlop || scaledDy > touchSlop) {
                if (isVpHorizontal == (scaledDy > scaledDx)) {
                    // Gesture is perpendicular, allow all parents to intercept
                    getParent().requestDisallowInterceptTouchEvent(false);
                } else {
                    float value = isVpHorizontal ? dx : dy;
                    if (canChildScroll(orientation, value)) {
                        getParent().requestDisallowInterceptTouchEvent(true);
                    } else {
                        getParent().requestDisallowInterceptTouchEvent(false);
                    }
                }
            }
        }
    }

    public void setParentViewPager(ViewPager2 parentViewPager) {
        this.parentViewPager = parentViewPager;
    }
}
